
// 字符串自变量定义请求方式
export type Method =
  | 'get' | 'GET'
  | 'delete' | 'DELETE'
  | 'head' | 'HEAD'
  | 'options' | 'OPTIONS'
  | 'post' | 'POST'
  | 'put' | 'PUT'
  | 'patch' | 'PATCH'

// 请求参数
export interface AxiosRequestConfig {
  url?: string;      // 定义axios混合类扩展方法后，url在axios.request（url）中传递
  method?: Method;
  data?: any;
  params?: any; 
  headers?: any;
  responseType?: XMLHttpRequestResponseType;    // 请求响应数据类型
  // type XMLHttpRequestResponseType = "" | "arraybuffer" | "blob" | "document" | "json" | "text";
  timeout?: number;                             // 超时时间 默认为0，永不超时
}

// 响应类型
export interface AxiosResponse<T = any> {
  data: T;              // 服务端返回数据
  status: number;         // http状态码
  statusText: string;     // http状态码对应的文本信息： ok， Not Found……
  headers: any;           // 响应头
  config: AxiosRequestConfig;  // 请求参数信息
  request: any;                // xhr对象
}

// ajax请求返回promise对象接口声明
export interface AxiosPromise<T = any> extends Promise<AxiosResponse<T>> {

}

// 错误处理类
export interface AxiosError extends Error {
  config: AxiosRequestConfig,
  code?: string;
  request: any;                 // xhr 对象
  response?: AxiosResponse;     // 网络错误、超时不会有response数据
  isAxiosError: boolean;
}

// 感叹号类型断言 url!(断言url不为空)

// Axios 类
export interface Axios {
  request<T = any>(config: AxiosRequestConfig): AxiosPromise<T>;
  get<T = any>(url: string, config?: AxiosRequestConfig): AxiosPromise<T>;
  delete<T = any>(url: string, config?: AxiosRequestConfig): AxiosPromise<T>;
  head<T = any>(url: string, config?: AxiosRequestConfig): AxiosPromise<T>;
  options<T = any>(url: string, config?: AxiosRequestConfig): AxiosPromise<T>;
  post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise<T>;
  put<T = any>(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise<T>;
  patch<T = any>(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise<T>;
}

// 一个混合类型接口
export interface AxiosInstance extends Axios {
  <T = any>(config: AxiosRequestConfig): AxiosPromise<T>;
  // 函数重载： 实现axios(url, [config])(可以直接传url)
  <T = any>(url: string, config?: AxiosRequestConfig): AxiosPromise<T>
}


// interceptors 
// 返回number原因是给eject函数使用
// 每创建一个use方法都返回一个id(数组下标)，根据id来删除
// 接口描述一个函数，可以在函数前加一个别名： 此时定义的是类中函数
export interface AxiosInterceptorManager<T> {
  use(resolved: ResolvedFn<T>, rejected?: RejectedFn): number
  eject(id: number): void
} 

// use一个函数参数，需要定义成泛型，原因如下：
// 对于请求拦截器参数： AxiosRequestConfig， 
// 对于响应拦截器参数： AxiosResponse
export interface ResolvedFn<T> {
  (val: T): T | Promise<T>
}

// use第二个回调函数，错误类型可以是任何类型
export interface RejectedFn {
  (error: any): any
}